package proj1.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import proj1.constants.C.COMPARATOR;
import proj1.oracle.OracleDB;
import proj1.util.Logger;
import proj1.util.StringUtil;

public class Make {
	private static Logger log = Logger.getLogger(Make.class);
	public static final String TABLE_NAME = "MAKE";
	
	// I N S T A N C E  V A R I A B L E S
	private final String tableId; // COD column
	private String make; // MAK column
	private String makeNo; // MNO column
	private Integer hashCode = null; // lazy initialize
	
	/**
	 * Constructor. Creates a {@code Make} object from the set of database tuples
	 * @param makeNo The MNO column value
	 * @param make The MAK column value
	 * @param tableId The COD column value
	 */
	public Make(String makeNo, String make, String tableId){
		this.makeNo = makeNo;
		this.make = make;
		this.tableId = tableId;
	}
	
	/**
	 * <pre>
	 * Returns a sorted set of {@link proj1.dao.Model Models} for this Maker.
	 * </pre>
	 * @return A sorted set of {@code Models} for this Maker.
	 */
	public Set<Model> getModels(){
		return Model.getModels(this);        
	}
	
	public String getMake(){
		return make;
	}
	
	public String getMakeNo(){
		return makeNo;
	}
	
	public String getTableId(){
		return tableId;
	}
	
	@Override
	public boolean equals(Object other){
		if(other == null)
			return false;
		
		if(!(other instanceof Make))
			return false;
		
		Make oMake = (Make) other;
		return make.equals(oMake.make) && makeNo.equals(oMake.makeNo) && tableId.equals(oMake.tableId);
	}
	
	@Override 
	public int hashCode(){
		// Synchronize the object to avoid corrupt hash values due to concurrent modification
		synchronized(this){
			if(hashCode == null){
				hashCode = 17;
				hashCode = 37 * hashCode + (this.make != null ? this.make.hashCode() : 0);
				hashCode = 37 * hashCode + (this.makeNo != null ? this.makeNo.hashCode() : 0);
				hashCode = 37 * hashCode + (this.tableId != null ? this.tableId.hashCode() : 0);
			}
		}
		return hashCode.intValue();
	}
	
	// Display the Make name plus the parenthesized MakeNo
	@Override
	public String toString(){
		return StringUtil.ifNull(make, "") + " (" + StringUtil.ifNull(makeNo, "") + ")";
	}
	
	// P U B L I C   S T A T I C   M E T H O D S
	/** 
	 * <pre>
	 * Retrieves all {@code Make} tuples from the database and returns them as a set of {@code Make} objects.
	 * </pre>
	 * @return A set of sorted ({@link #makeComparator}) Make objects from the database.
	 */
	public static Set<Make> getAllMakes(){
		return getMakes(null);
	}
	
	/**
	 * <pre>
	 * Retrieves all {@code Make} tuples from the database which match the specified criteria. 
	 * If no criteria is specified, all tuples will be returned.
	 * </pre>
	 * @param criteria A {@code Map<Attribute,String>} of key/value pairs to use as database selection criteria
	 * @return A set of sorted ({@link #makeComparator}) Make objects from the database.
	 */
	public static Set<Make> getMakes(Map<String,String> criteria){
		OracleDB conn = OracleDB.getInstance();
		String query = "SELECT * from " + TABLE_NAME;
		
		// If any criteria were passed in, apply them
		if(criteria != null){
			boolean first = true; // don't apply comma to first
			for(Map.Entry<String,String> entry : criteria.entrySet())
				query += (first ? " " : " , ") + entry.getKey() + "=" + entry.getValue(); 
		}
		// Use the default comparator for sorting
		Set<Make> result = new TreeSet<Make>(COMPARATOR.MAKE);
		
		// For each item in the results, create a new Make object and add it to the result set
		try {
			// Execute the query via the OracleDB connection
			ResultSet rs = conn.executeQuery(query);
			
			while(rs.next())
				result.add(
					new Make(
						rs.getString("MNO"), 
						rs.getString("MAK"), 
						rs.getString("COD")
					)
				);
		} catch (SQLException e) {
			log.error("A SQL Exception occurred during Make fetch.", e);
		}
        return result;
	}
}

